package com.zzcoder.mall.security.config;

import com.zzcoder.mall.security.component.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import static org.springframework.security.config.Customizer.withDefaults;

@Configuration
@EnableWebSecurity
public class CommonSecurityConfig {
    @Value("${secure.login-process-url}")
    private String loginProcessingUrl;
    @Value("${secure.logout-url}")
    private String logoutUrl;

    private WhiteListConfig whiteListConfig;
    private UserDetailsService userDetailsService;
    private AuthenticationSuccessHandler authenticationSuccessHandler;
    private VerifyCodeAuthenticationProvider verifyCodeAuthenticationProvider;
    private LogoutSuccessHandlerImpl logoutSuccessHandler;
    private AuthenticationEntryPointImpl authenticationEntryPoint;
    private AuthenticationFailureHandlerImpl authenticationFailureHandler;
    private AccessDeniedHandlerImpl accessDeniedHandler;
    private TokenAuthenticationFilter tokenAuthenticationFilter;

    public CommonSecurityConfig(
            WhiteListConfig whiteListConfig,
            UserDetailsService userDetailsService,
            AuthenticationSuccessHandler authenticationSuccessHandler,
            VerifyCodeAuthenticationProvider verifyCodeAuthenticationProvider,
            LogoutSuccessHandlerImpl logoutSuccessHandler,
            AuthenticationEntryPointImpl authenticationEntryPoint,
            AuthenticationFailureHandlerImpl authenticationFailureHandler,
            AccessDeniedHandlerImpl accessDeniedHandler,
            TokenAuthenticationFilter tokenAuthenticationFilter
    ) {
        this.whiteListConfig = whiteListConfig;
        this.userDetailsService = userDetailsService;
        this.authenticationSuccessHandler = authenticationSuccessHandler;
        this.verifyCodeAuthenticationProvider = verifyCodeAuthenticationProvider;
        this.logoutSuccessHandler = logoutSuccessHandler;
        this.authenticationEntryPoint = authenticationEntryPoint;
        this.authenticationFailureHandler = authenticationFailureHandler;
        this.accessDeniedHandler = accessDeniedHandler;
        this.tokenAuthenticationFilter = tokenAuthenticationFilter;
    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        //开启基础验证
        http.httpBasic(withDefaults());

        //api授权
        for (String url : whiteListConfig.getUrls()) {
            http.authorizeRequests().antMatchers(url).permitAll();
        }

        http.authorizeRequests()
                //其余请求全部需要登录后访问
                .anyRequest().authenticated();

        //开启表单登录
        http.formLogin()
                .loginProcessingUrl(this.loginProcessingUrl)//登录成功处理
                .successHandler(this.authenticationSuccessHandler)
                .failureHandler(this.authenticationFailureHandler);
        //退出登录
        http.logout()
                .logoutUrl(this.logoutUrl)
                .logoutSuccessHandler(this.logoutSuccessHandler);
        //没有权限
        http.exceptionHandling().accessDeniedHandler(this.accessDeniedHandler);
        //未登录
        http.exceptionHandling().authenticationEntryPoint(this.authenticationEntryPoint);
        //支持跨域
        http.cors();
        //使用token, 禁用csrf
        http.csrf().disable();
        //禁用session
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

        http.userDetailsService(this.userDetailsService);
        // 添加验证码校验
        http.authenticationProvider(this.verifyCodeAuthenticationProvider);

        http.addFilterBefore(tokenAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);

        return http.build();
    }
}
